package com.gateway.config;

import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;

import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Configuration
public class GatewayConfiguration {
    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolvers,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolvers.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    //    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("url-proxy",r -> r.path("/jsontom/**")
                        .or().query("name","tom")
                        .filters(f -> f.prefixPath("/app"))
                        .uri("http://localhost:8080/jsontom")
                ).build();
    }

    //注入一个全局限流过滤器SentinelGatewayFilter
    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter(){
        return new SentinelGatewayFilter();
    }

    //注入限流异常处理器
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelFallbackHandler sentinelGatewayBlockExceptionHandler(){
        return new SentinelFallbackHandler();
    }

    @PostConstruct
    public void doInit(){
//        initGatewayRules();
//        initGatewayRulesGroup();
    }

    // route限流初始化限流规则
    private void initGatewayRules(){
        Set<GatewayFlowRule> rules = new HashSet<>();
        GatewayFlowRule gatewayFlowRule = new GatewayFlowRule("spring-cloud-consumer1")
                .setCount(1)// 限流阈值
                .setIntervalSec(1);// 统计时间窗口，单位是秒
        rules.add(gatewayFlowRule);
        GatewayRuleManager.loadRules(rules);
    }

    // 分组限流初始化限流规则
    private void initGatewayRulesGroup(){
        Set<GatewayFlowRule> rules = new HashSet<>();
        GatewayFlowRule gatewayFlowRule = new GatewayFlowRule("first_customized_api")
                // RESOURCE_MODE_CUSTOM_API_NAME表示是用户自定义的API分组限流，默认是route限流
                .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
                .setCount(1)// 限流阈值
                .setIntervalSec(1);// 统计时间窗口，单位是秒
        rules.add(gatewayFlowRule);
        GatewayRuleManager.loadRules(rules);
        initCustomizedApis();
    }

    // 分组限流
    private void initCustomizedApis(){
        Set<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition apiDefinition = new ApiDefinition("first_customized_api");
        apiDefinition.setPredicateItems(new HashSet<ApiPredicateItem>(){{
            //URL_MATCH_STRATEGY_PREFIX表示前缀匹配，默认是精确匹配
//            add(new ApiPathPredicateItem().setPattern("/app/jsontom/**").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
            add(new ApiPathPredicateItem().setPattern("/ser/**").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
        }});
        definitions.add(apiDefinition);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }

}
